<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .active{color:red}
    </style>
</head>
<body>
    <p>文字</p>
    <p>文字2</p>
<script>
/* 
1. this不同运用场景，如果取值
2. 手写bind函数
3. 闭包应用场景，举例
*/
// 创建10个a标签点击弹出对应序号
let i,a;
for( i = 0; i < 10; i++){
    a =document.createElement("a");
    a.innerHTML = i +"<br>";
    a.addEventListener("click",e=>{
        e.preventDefault();
        alert(i);
    })
    document.body.appendChild(a);
}

/*
let a;
for( var i = 0; i < 10; i++){
    !function(i){
    a =document.createElement("a");
    a.innerHTML = i +"<br>";
    a.addEventListener("click",e=>{
        e.preventDefault();
        alert(i);
    })
    document.body.appendChild(a);
    }(i)
} 
*/


// 作用域
// 全局作用域，函数作用域，块作用域（ES6 新增）

//  ES6块级作用域名
if(true){
    let x = 100;
}
console.log(x); //会报错

//  自由变量
//  01 一个变量在当前作用域没有定义，但被使用了
//  02 向上级作用域，一层层寻找，直到找到为止
//  03 如果到全局作用域都没有找到，则报错 xxx is not defined


//  闭包:作用域应用的特殊情况
//  01 函数作为参数被传递
//  02 函数作为返回值被返回

//  函数作为返回值
function create(){
    let a = 100;
    return function(){
        console.log(a)
    }
}
let fn = create();
let a = 200;
fn();

// 函数作为参数
function print(fn){
    let a = 200;
    fn();
}
let a = 100;
function fn(){
    console.log(a);
}
print(fn);
//  闭包:自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方



//  this  在函数执行的时候确定的,不是在函数定义的时候确定的
//  作为普通函数
//  使用call apply bind
//  作为对象方法被调用
//  class方法中被调用
//  箭头函数
 
//   普通函数
function fn1(){
    console.log(this);
}
fn1() //  window

fn1.call({x:100}) // {x:100}

const fn2 = fn1.bind({x:200});
fn2() // {x:200}

const xhangsan  = {
    name:"张三",
    sayHi(){
        // this 即是当前对象
        console.log(this);
    },
    wait(){
        setTimeout(function(){
            //  this === window;
            console.log(this)
        })
    }
}

const xhangsan  = {
    name:"张三",
    sayHi(){
        // this 即是当前对象
        console.log(this);
    },
    waitAgain(){
        setTimeout(()=>{
            //  this === window;
            console.log(this)
        })
    }
}
// 箭头函数this取上级作用域this 

//  类中的this 指向类的实例
class People{
    constructor(name){
        this.name = name;
        this.age = 20;
    }
    sayHi(){
        console.log(this)
    }
}



//  bind函数应用
function fn1(a,b,c){
    console.log('this',this);
    console.log(a,b,c);
    return 'this is fn1';
}
const fn2 = fn1.bind({x:100},10,20,30);
fn2();
// bind 怎么来  fn1.__proto__===Function.prototype
// Function.prototype.bind

// 模拟参数
Function.prototype.bind1 = function(){
    // 第一个参数位this 参数很多
    // 将参数拆解为数据组
    const args = Array.prototype.slice.call(arguments);
    //  获取this(数组的第一个参数)
    const t = args.shift();
    //  fn1.bind(...) 中的fn1
    const self = this;

    // 返回一个函数
    return function (){
        return self.apply(t,args);
    }

}
fun1.bind1({x:55},10,20,30);

// 小结
//  作用域和自由变量
//  闭包，函数返回，函数当参数传入 自由变量规则
//  this

// 原型this
xialuo.__proto__.name
//  Student.prototype 没name
// xialuo.sayHi() 类型 xialuo.__proto__.sayHi.call(xiaoluo)
</script>
</body>
</html>